<?php
declare(strict_types=1);
namespace Helper;

use Swoole\Http\Response;
use Swoole\Table;
use Swoole\Timer;

class ValidateCode
{
	private string $charset = 'abcdefghkmnprstuvwxyzABCDEFGHKMNPRSTUVWXYZ23456789';//随机因子
	private string $code="";//验证码
	private int $codelen = 5;//验证码长度
	private int $width = 300;//宽度
	private int $height = 80;//高度
	private mixed $img;//图形资源句柄
	private mixed $font;//指定的字体
	private int $fontsize = 45;//指定字体大小
	private $fontcolor;//指定字体颜色
	private Response $response;//指定字体颜色
    private $color;
    private int $length=49;
    public Table $T_VC;
    //生成随机码
    /**
     * @title    table_unlock
     *
     * @param     $key
     * @param int $micro_time
     */
    public function table_check(string $key):bool
    {
        return $this->T_VC->exist($key);
    }
    public function table_lock(string $key,int $micro_time = 60):void
    {
        $this->T_VC->set($key, ['lock' => time()+$micro_time]);
        Timer::after($micro_time*1000, function () use ($key) {
            $this->T_VC->set($key, ['lock' => 0]);
            $this->T_VC->del($key);
        });
    }

    /**
     * @title    table_unlock
     *
     * @param     $key
     * @param int $micro_time
     */
    public function table_unlock(string $key, int $micro_time = 0)
    {
        if ($micro_time == 0) {
            $this->T_VC->set($key, ['lock' => 0]);
            $this->T_VC->del($key);
        } else {
            Timer::after($micro_time*1000, function () use ($key) {
                $this->T_VC->set($key, ['lock' => 0]);
                $this->T_VC->del($key);
            });
        }
    }
	//构造方法初始化
	public function  __construct($response)
	{
	    $n = mt_rand(3,5);
	    if($n<3){
	        $this->fontsize=50;
        }else{
            $this->fontsize=45;
        }
		$this->font = __SYSDIR__ . ($n<3?'Thin.otf':'HansKendrickV.ttf');//注意字体路径要写对，否则显示不了图片
		$this->response = $response;
        $this->T_VC=$_ENV['Table']['Vc'];
	}

	//生成随机码
	private function createCode(): void
    {
		$_len = $this->length;
		for ($i = 0; $i < $this->codelen; $i++) {
			$this->code .= $this->charset[mt_rand(42, $_len)];
		}
	}

	//生成背景
	private function createBg(): void
    {
		mt_srand();
		$this->img = imagecreatetruecolor($this->width, $this->height);
		$color = imagecolorallocatealpha($this->img, mt_rand(200, 255), mt_rand(200, 255), mt_rand(200, 255),mt_rand(1,5));
		imagefilledrectangle($this->img, 0, $this->height, $this->width, 0, $color);
        $this->color=[];
        for ($i = 0; $i < 20; $i++) {
            $this->color[] = imagecolorallocatealpha($this->img, mt_rand(80, 157), mt_rand(80, 157), mt_rand(80, 157),mt_rand(50,70));
            $this->fontcolor[] = imagecolorallocatealpha($this->img, mt_rand(0, 100), mt_rand(0, 100), mt_rand(0, 100),mt_rand(1,5));
        }
	}

	//生成文字
	private function createFont(): void
    {
		mt_srand();
		$_x = $this->width / $this->codelen;
		for ($i = 0; $i < $this->codelen; $i++) {
            $color=$this->color[mt_rand(0,19)];
            $color2= $this->fontcolor[mt_rand(0,19)];
            $left= intval($_x * $i + mt_rand(10, 20)) ;
            $top = intval($this->height/1.2);
            imagettftext($this->img, $this->fontsize, mt_rand(-40, 40), $left, $top,$color2, $this->font, $this->code[$i]);
            imagettftext($this->img, $this->fontsize*0.9, mt_rand(-40, 40), $left, $top, $color, $this->font, $this->charset[mt_rand(0,41)]);
		}
	}

	//生成线条、雪花
	private function createLine(): void
    {
		mt_srand();
        $colors = $this->color;
        $max = count($colors)-1;
		for ($i = 0; $i <20; $i++) {
            $color=$this->color[mt_rand(0,$max)];
            $left= intval(mt_rand(5, $this->width-5));
            $top = intval(mt_rand(5,$this->height-5));
           imagettftext($this->img,mt_rand(intval($this->fontsize*0.8),intval($this->fontsize*1.4)), mt_rand(-100, 100), $left, $top,$color, $this->font,$this->charset[mt_rand(0,41)]);
		}
        imagefilter($this->img,7);
	}

	//输出
	private function outPut(): false|string
    {
		ob_start();
		imagepng($this->img);
		$data = ob_get_contents();
        //$data = str_replace('PNG','png',$data);
		imagedestroy($this->img);
		ob_end_clean();
		return $data;
	}

	//对外生成
	public function do_img(int $n=5): false|string
    {
		$this->codelen=$n;
		$this->createBg();
        $this->createCode();
        $this->createLine();
        $this->createFont();
		return $this->outPut();
	}

    /**
     * @title 验证
     * @param $xcode
     * @param $code
     * @param int $time_out
     * @return bool
     */
	public function verify(string $xcode, $code, int $time_out=60): bool
    {
        $key = md5($xcode);
        if(!$this->table_check($key)){
            return false;
        }
        $v_code = substr($xcode,20,-20);
        if(empty($v_code)||empty($code)){
            return false;
        }
        $v_code = xn_decrypt($v_code);
        if(empty($v_code)){
            return false;
        }
        $time =intval(substr($v_code,0,10));
        if($time+$time_out<time()){
            return false;
        }
        if(substr($v_code,10)==$code){
            $this->table_unlock($key);
            return true;
        }
		return false;
	}

	//获取验证码
	public function getCode($name = 'xcode',$time=60): string
    {
		$code = strtolower($this->code);
        $xcode = xn_rand(20).xn_encrypt(time().$code).xn_rand(20);
        $m5= md5($xcode);
		$this->response->cookie(md5($name),$xcode,time() +$time,'/',"",false,true);
        $this->table_lock($m5,$time);
		return $code;
	}

}
?>